package com.zxshhy.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: dengrd
 * @Date: 2018/9/10
 * @Description:
 */

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * 缓存默认超时时间
     */
    private final static int DEFAULT_TTL = 30 * 60;

    /**
     * 自定义的缓存key的生成策略
     * @return 自定义策略生成的key
     */
    @Override
    @Bean
    public KeyGenerator keyGenerator() {
        return (Object target, Method method, Object... params) -> {
            StringBuffer sb = new StringBuffer();
            sb.append(target.getClass().getName());
            sb.append(method.getName());
            for (Object obj : params) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return new RedisCacheManager(
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                this.getRedisCacheConfigurationWithTtl(DEFAULT_TTL),
                this.getRedisCacheConfigurationMap()
        );
    }

    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(2);
        redisCacheConfigurationMap.put("AUTH:PERMS", this.getRedisCacheConfigurationWithTtl(60 * 60 * 24 * 30));
        redisCacheConfigurationMap.put("AUTH:GROUPS", this.getRedisCacheConfigurationWithTtl(60 * 60 * 24 * 30));
        redisCacheConfigurationMap.put("AUTH:MENUS", this.getRedisCacheConfigurationWithTtl(60 * 60 * 24 * 30));
        redisCacheConfigurationMap.put("AUTH:FEATURES", this.getRedisCacheConfigurationWithTtl(60 * 60 * 24 * 30));
        redisCacheConfigurationMap.put("AUTH:BIZ_FEATURES", this.getRedisCacheConfigurationWithTtl(60));
        redisCacheConfigurationMap.put("AUTH:WXAPP_FEATURES", this.getRedisCacheConfigurationWithTtl(60 * 10));
        redisCacheConfigurationMap.put("AUTH:MP_APP_ID", this.getRedisCacheConfigurationWithTtl(60 * 10));
        redisCacheConfigurationMap.put("BIZ:BID", this.getRedisCacheConfigurationWithTtl(60 * 10));
        redisCacheConfigurationMap.put("BIZ:SID", this.getRedisCacheConfigurationWithTtl(60 * 10));
        redisCacheConfigurationMap.put("BIZ:UID", this.getRedisCacheConfigurationWithTtl(60 * 10));
        return redisCacheConfigurationMap;
    }

    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
                RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(new GenericFastJsonRedisSerializer())
        ).entryTtl(Duration.ofSeconds(seconds));
        return redisCacheConfiguration;
    }

    /**
     * RedisTemplate配置
     * @param redisConnectionFactory redisConnectionFactory
     * @param redisConnectionFactory redisConnectionFactory
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置value 序列化
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());
        //设置key 序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
